#ifndef _SERVER_PROTOCOL_HANDLER_BASE_HPP
#define _SERVER_PROTOCOL_HANDLER_BASE_HPP

#include <functional>
#include <memory>
#include <optional>
#include <string>
#include <tuple>
#include <vector>

namespace engineserver
{
/**
 * @brief ProtocolHandler interface
 *
 * ProtocolHandler interface, it is used to implement a protocol handler for the server.
 * The protocol handler is used to process the data received in stream mode, and to generate the data to send.
 * The protocol handler is used by the server to process the data received from the client, and to generate the data to
 * send to the client.
 *
 */
class ProtocolHandler
{

public:
    ProtocolHandler() = default;
    virtual ~ProtocolHandler() = default;

    /**
     * @brief Process the data stream received from the client
     *
     * Process the data stream received from the client, it is used to process the data received in stream mode.
     * The data is received in chunks, and the protocol handler is used to process the data received in chunks and
     * generate the messages to be processed by the server.
     * The chunk are received in order but the order of processing is not guaranteed to be the same.
     * @param data Data received from the client
     * @return std::optional<std::vector<std::string>> Vector of messages generated by the protocol handler
     *
     * @throw std::runtime_error If the data received is not valid, it throws an exception and the connection should be
     * closed.
     */
    virtual std::optional<std::vector<std::string>> onData(std::string_view data) = 0;

    /**
     * @brief Process the message received from the server
     *
     * Process the message received from the server, it is used to process the message received from the server and
     * generate the data to send to the client.
     * @param message Message received from the server
     * @param callbackFn A callback function that will be invoked with the generated response.
     *
     * @note If the method throws an exception, the connection should be closed witout sending any data to the client.
     * @note The message is the response of processing the message received from the client.
     */
    virtual void onMessage(const std::string& message, std::function<void(const std::string&)> callbackFn) = 0;

    /**
     * @brief Generate the data to send to the client
     *
     * Generate the data to send to the client, it is used to generate the data to send to the client,
     * The message is the response of processing the message received from the client.
     * @param message Message to send to the client
     * @return Data to send to the client, and the size of the data
     *
     * @note this method not throw any exception.
     */
    virtual std::tuple<std::unique_ptr<char[]>, std::size_t> streamToSend(std::shared_ptr<std::string> message) = 0;

    /**
     * @brief Generate the data to send to the client
     *
     * Generate the data to send to the client, it is used to generate the data to send to the client,
     * The message is the response of processing the message received from the client.
     * @param message Message to send to the client
     * @return Data to send to the client, and the size of the data
     *
     * @note this method not throw any exception.
     */
    virtual std::tuple<std::unique_ptr<char[]>, std::size_t> streamToSend(const std::string& message) = 0;

    /**
     * @brief Get busy response to send to the client (if the server is busy)
     *
     * Get busy response to send to the client (if the server is busy), it is used to generate the data to send to the
     * client when the server is busy, this method not throw any exception.
     * This should be a static method (precompiled response).
     * @return Data to send to the client, and the size of the data
     */
    virtual std::tuple<std::unique_ptr<char[]>, std::size_t> getBusyResponse() = 0;

    /**
     * @brief Get error response to send to the client (if the server has an error)
     *
     * Get error response to send to the client (if the server has an error), it is used to generate the data to send to
     * the client when the server has an error, this method not throw any exception.
     * @return Data to send to the client
     */
    virtual std::string getErrorResponse() = 0;
};

// ProtocolHandler Factory
class ProtocolHandlerFactory
{
public:
    ProtocolHandlerFactory() = default;
    virtual ~ProtocolHandlerFactory() = default;

    virtual std::shared_ptr<ProtocolHandler> create() = 0;
};

} // namespace engineserver

#endif // _SERVER_PROTOCOL_HANDLER_BASE_HPP
